package sample.service.imagehelper.impl;

import javax.annotation.Resource;

import org.apache.commons.codec.binary.Base64;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.owasp.validator.html.AntiSamy;
import org.owasp.validator.html.CleanResults;
import org.owasp.validator.html.Policy;
import org.springframework.stereotype.Service;

import sample.intf.imagehelper.service.ExistingKeyFoundAction;
import sample.intf.imagehelper.service.GenerateImageInfoAction;
import sample.intf.imagehelper.service.IImageHelperService;
import sample.intf.imagehelper.service.TImageInfo;

@Service
public class ImageHelperService implements IImageHelperService {

	@Resource
	Policy antisamyPolicy;

	public CleanResults sanitizeHtml(String html) throws Exception {
		AntiSamy as = new AntiSamy();
		CleanResults cr = as.scan(html, antisamyPolicy);
		return cr;
	}

	@Override
	public String transform(String html, ExistingKeyFoundAction existingKeyFoundAction,
			GenerateImageInfoAction generateImageInfoAction) throws Exception {
		// 构造DocumentFragment
		Document documentFragment = stringToDocument(html);
		// 替换图片
		replaceImageSrc(documentFragment, existingKeyFoundAction, generateImageInfoAction);
		// 净化文档
		return sanitizeHtml(documentFragment.toString()).getCleanHTML();
	}

	private Document stringToDocument(String content) throws Exception {
		return Jsoup.parseBodyFragment(content);
	}

	private void replaceImageSrc(Document document, ExistingKeyFoundAction existingKeyFoundAction,
			GenerateImageInfoAction generateImageInfoAction) {
		Elements imgs = document.getElementsByTag("img");
		for (Element img : imgs) {
			// 已经有key了
			String key = img.attr("data-key");
			if (key != null && !"".equals(key.trim())) {
				boolean acceptThisKey = true;
				try {
					if (existingKeyFoundAction != null)
						acceptThisKey = existingKeyFoundAction.check(key);
				} catch (Exception e) {
					// Do nothing
				}
				if (acceptThisKey)
					continue;
			}
			// 处理
			String src = img.attr("src");
			if (src == null)
				continue;
			if (src.startsWith("data:")) {
				// 提取内容
				ImageData imageData = null;
				try {
					imageData = parseImageData(src);
				} catch (Exception e) {
					// Do nothing
				}
				// 提取原文件名
				String originalFileName = img.attr("data-filename");
				img.removeAttr("data-filename");
				// 检查内容
				TImageInfo info = null;
				if (imageData != null) {
					// 调用回掉函数，获取新路径
					try {
						if (generateImageInfoAction != null)
							info = generateImageInfoAction.generate(originalFileName, imageData.getType(),
									imageData.getData());
					} catch (Exception e) {
						// Do nothing
					}
				}
				if (info == null)
					continue;
				// 检查新路径
				if (info.getKey() != null)
					img.attr("data-key", info.getKey());
				if (info.getSrc() != null)
					img.attr("src", info.getSrc());
			}
		}
	}

	private ImageData parseImageData(String data) throws Exception {
		if (data.startsWith("data:")) {
			data = data.substring(5); // data:
		}
		ImageData imageData = new ImageData();
		int iPos = data.indexOf(';');
		if (iPos < 0)
			throw new Exception();
		imageData.setType(data.substring(0, iPos));
		String image = data.substring(iPos + 1);
		if (!image.startsWith("base64,"))
			throw new Exception();
		image = image.substring(7); // base64,
		imageData.setData(Base64.decodeBase64(image));
		return imageData;
	}

	static class ImageData {
		private String type;
		private byte[] data;

		public String getType() {
			return type;
		}

		public void setType(String type) {
			this.type = type;
		}

		public byte[] getData() {
			return data;
		}

		public void setData(byte[] data) {
			this.data = data;
		}

	}
}
